Use PiecewiseSequence indices for FSL take#8800
Conversation
Merging this PR will regress 1 benchmark
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
aba7e4d to
3edf6c8
Compare
07fde63 to
3ecd955
Compare
3edf6c8 to
1748e31
Compare
3ecd955 to
98a9180
Compare
01e95cb to
eb83451
Compare
eb83451 to
e79ec4b
Compare
| S: crate::dtype::UnsignedPType, | ||
| L: crate::dtype::UnsignedPType, | ||
| { | ||
| validate_index_ranges(source.len(), starts, lengths, output_len)?; |
There was a problem hiding this comment.
the slice will validate them
| array.buffer::<D>().as_slice(), | ||
| indices_ref.len(), | ||
| )?; | ||
| let validity = array.validity()?.take(indices_ref)?; |
There was a problem hiding this comment.
eh, we need my refactor pr to extract the ref from view
| L: crate::dtype::UnsignedPType, | ||
| T: NativeDecimalType, | ||
| { | ||
| validate_index_ranges(values.len(), starts, lengths, output_len)?; |
There was a problem hiding this comment.
this is already validated by the result slice
There was a problem hiding this comment.
so imho you either keep this and convert the loop below all into unsafe accesses or remove this and use the optional getters on slice
| for (&start, &length) in starts.iter().zip_eq(lengths) { | ||
| let start = start.as_(); | ||
| let length = length.as_(); | ||
| result.extend_from_slice(&values[start..start + length]); |
There was a problem hiding this comment.
I think this would be better if you had the mutable result and then wrote directly into the next available range result[curr..][..length]
There was a problem hiding this comment.
So, I was a bit skeptical this would help (surely a sufficiently advanced compiler...).
I ran a benchmark for any subset of:
- replace extend_from_slice with mutable_result[cursor..][..length].copy_slice_from
- Verify all starts & starts + length are valid indices in a previous loop and use unsafe unchecked slicing.
On these data:
- Source data is just random u16s of size 1,000, 10,000, 100,000.
- Number of slices is 50.
- Slice lengths are normally distributed with mean 1/100 of source data length.
- Starts are uniformly randomly chosen but then sorted.
The cursor approach does seem noticeably better, particularly when the slices are mean 200 bytes. Also better for slices of mean 20 bytes but less significantly so.
| source len | extend | cursor | extend unchecked | cursor unchecked |
|---|---|---|---|---|
| 1,000 | 275.7 ns, 3.60 GB/s | 249.7 ns, 3.98 GB/s | 283.6 ns, 3.50 GB/s | 260.1 ns, 3.82 GB/s |
| 10,000 | 247.1 ns, 38.3 GB/s | 208.0 ns, 45.5 GB/s | 254.9 ns, 37.1 GB/s | 223.7 ns, 42.3 GB/s |
| 100,000 | 2.020 µs, 47.7 GB/s | 2.062 µs, 46.8 GB/s | 2.020 µs, 47.7 GB/s | 2.062 µs, 46.8 GB/s |
There was a problem hiding this comment.
I'm gonna create a follow up PR that address this.
|
|
||
| let (new_elements, new_len) = | ||
| take_non_empty_non_degenerate_elements::<I>(array, indices_array, ctx)?; | ||
| let new_validity = if array.dtype().is_nullable() || indices_nullability.is_nullable() { |
There was a problem hiding this comment.
I think validity take already handles this
robert3005
left a comment
There was a problem hiding this comment.
I think we have to audit the validation from the compute and verify that we do not do the work twice. We have to audit exactly but ideally we'd not validate and figure out how to make operations safe by default even given bad input.
6eb0c92 to
16ca5dc
Compare
b615895 to
6dcc52a
Compare
6dcc52a to
a2cbdf0
Compare
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
a2cbdf0 to
d694338
Compare
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
89e4da2 to
2a33748
Compare
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
|
I cannot replicate the two benchmark slowdowns locally. |
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
|
The copy_ benchmark slowdowns are resolved by #8832 |
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Summary
Ports the TakeSlices-style optimization to
Take(elements, PiecewiseSequenceArray)instead of introducing a value-wrapper API.1, then callselements.take(piecewise_indices).PiecewiseSequenceArrayindices and gather contiguous ranges only whenmultipliersis a constant unsigned1; non-unit multipliers fall back through normal materialized-index take.start + j * multipliersequences, while the current optimized consumers stay explicitly contiguous.Validation
cargo fmt -p vortex-arraycargo test -p vortex-array piecewise_sequencecargo check -p vortex-arraycargo check -p vortex-array --benchesgit diff --check